#if (FEATURE_MODE == 0)
/**
 @file sys_usw_npm.c

 @date 2014-10-28

 @version v3.0


*/

/****************************************************************
 *
 * Header Files
 *
 ***************************************************************/
#include "ctc_error.h"
#include "ctc_npm.h"
#include "ctc_packet.h"
#include "ctc_xdata.h"

#include "sys_usw_common.h"
#include "sys_usw_npm.h"
#include "sys_usw_nexthop_api.h"
#include "sys_usw_dmps.h"
#include "sys_usw_dma.h"
#include "sys_usw_register.h"
#include "sys_usw_interrupt.h"
#include "sys_usw_eunit.h"
#include "sys_usw_acl_api.h"
#include "sys_usw_stats_api.h"
#include "sys_usw_xdata_api.h"

#include "drv_api.h"
#include "usw/include/drv_chip_ctrl.h"
/****************************************************************************
 *
* Defines and Macros
*
*****************************************************************************/
#define SYS_NPM_IM_MAX_DELAY_PROFILE  1024
#define SYS_NPM_IM_MAX_SESSION        1024
#define SYS_NPM_IM_MAX_DELAY_PROFILE_ECPU  1024
#define SYS_NPM_IM_MAX_LOSS_PROFILE   7
#define SYS_NPM_IRQ_NPM_IM_LOSS_PROFILE1 64
#define SYS_NPM_IM_GLOABL_ENABLE_PROFILE_ID (SYS_NPM_IM_MAX_LOSS_PROFILE + SYS_NPM_IM_MAX_DELAY_PROFILE_ECPU)
#define SYS_NPM_IM_IS_IP(type) ((CTC_NPM_IM_TYPE_IPV4 == type) || (CTC_NPM_IM_TYPE_IPV6 == type))
/****************************************************************************
*
* Global and Declaration
*
*****************************************************************************/
extern sys_npm_master_t* g_npm_master[CTC_MAX_LOCAL_CHIP_NUM_PP];

struct sys_npm_im_profile_s
{
    uint32 interval_thrd : 10,
           interval_count : 10,
           enable : 1,
           loss_color : 1,
           type : 3,
           rsv : 7;
};
typedef struct sys_npm_im_profile_s sys_npm_im_profile_t;

typedef struct sys_npm_traverse_im_data_s
{
    uint8 lchip;
    uint8 loss_prof_id;
    uint8 loss_color;
    ctc_npm_im_event_t *p_loss_event;
}sys_npm_traverse_im_data_t;
/****************************************************************************
 *
 * Function
 *
 *****************************************************************************/

#define __INTERNAL_FUNC__
STATIC int32
_sys_usw_npm_im_flow_free_node_data(void* node_data, void* user_data)
{
    if (node_data)
    {
        mem_free(node_data);
    }
    return 1;
}

STATIC sys_npm_im_flow_hash_t*
_sys_usw_npm_im_flow_lookup_hash(uint8 lchip, sys_npm_im_flow_hash_t* p_im_flow)
{
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "    flow_id = %u\n", p_im_flow->flow_id);

    return ctc_hash_lookup(g_npm_master[lchip]->p_npm_im_flow_hash, p_im_flow);
}

STATIC sys_npm_im_flow_hash_t*
_sys_usw_npm_ilm_get_im_flow_hash(uint8 lchip, uint32 flow_id)
{
    sys_npm_im_flow_hash_t im_flow_hash_info;
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    sal_memset(&im_flow_hash_info, 0, sizeof(sys_npm_im_flow_hash_t));
    im_flow_hash_info.flow_id = flow_id;
    return _sys_usw_npm_im_flow_lookup_hash(lchip, &im_flow_hash_info);
}

STATIC int32
_sys_usw_npm_im_flow_add_hash(uint8 lchip, sys_npm_im_flow_hash_t* p_im_flow)
{
    sys_npm_im_flow_hash_t* p_im_flow_hash_ret_node = NULL;

    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    p_im_flow_hash_ret_node = ctc_hash_insert(g_npm_master[lchip]->p_npm_im_flow_hash, p_im_flow);
    if (NULL == p_im_flow_hash_ret_node)
    {
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [NPM] No Memory \n");
        return CTC_E_NO_MEMORY;
    }
    return CTC_E_NONE;
}

STATIC int32
_sys_usw_npm_im_flow_remove_hash(uint8 lchip, sys_npm_im_flow_hash_t* p_im_flow)
{
    sys_npm_im_flow_hash_t* p_node = NULL;
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    p_node = ctc_hash_remove(g_npm_master[lchip]->p_npm_im_flow_hash, p_im_flow);
    if (p_node)
    {
        mem_free(p_node);
    }

    return CTC_E_NONE;
}

STATIC uint32
_sys_usw_npm_im_flow_hash_make(sys_npm_im_flow_hash_t* p_im_flow)
{
    return p_im_flow->flow_id;
}

STATIC bool
_sys_usw_npm_im_flow_hash_cmp(sys_npm_im_flow_hash_t* p_im_flow0,
                              sys_npm_im_flow_hash_t* p_im_flow1)
{
    return (p_im_flow0->flow_id== p_im_flow1->flow_id);
}

STATIC int32
_sys_usw_npm_im_cmp_metadata(void* bucket_data, void* user_data)
{
    uint16 metadata = 0;
    sys_npm_im_flow_hash_t* p_im_flow_hash = NULL;
    uint8 is_find = 0;

    p_im_flow_hash = (sys_npm_im_flow_hash_t*)bucket_data;
    metadata = ((sys_traverse_t*)user_data)->value1;

    if ((metadata == p_im_flow_hash->metadata)
       || (metadata == (p_im_flow_hash->metadata+1)))
    {
        ((sys_traverse_t*)user_data)->value2 = p_im_flow_hash->flow_id;
        is_find = 1;
    }
    return is_find?-1:0;
}

#if (SDK_WORK_PLATFORM == 0)
#if defined E_UNIT && (FEATURE_MODE == 0)
STATIC int32
_sys_usw_npm_im_set_ecpu(uint8 lchip, void* p_value)
{
    /*write to ECPU*/
    if (MCHIP_EUNIT(lchip) && MCHIP_EUNIT(lchip)->set_cfg)
    {
        CTC_ERROR_RETURN(MCHIP_EUNIT(lchip)->set_cfg(lchip, SYS_EUNIT_CFG_NPM_IM, p_value));
    }
   return CTC_E_NONE;
}
#endif
#endif

STATIC int32
_sys_usw_npm_im_set_flow_property(uint8 lchip, ctc_npm_im_flow_property_t* p_npm_im_pro, sys_npm_im_flow_hash_t* p_im_flow_hash)
{
    int32 ret = CTC_E_NONE;
    uint32 offset = 0;
    uint32 cmd = 0;
    uint32 value = 0;
    sys_usw_opf_t   opf;

    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));

    if (!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    CTC_PTR_VALID_CHECK(p_npm_im_pro);
    CTC_PTR_VALID_CHECK(p_npm_im_pro->value);
    CTC_MAX_VALUE_CHECK(p_npm_im_pro->flow_id, 0xFFFFF);

    value = *(uint32*)(p_npm_im_pro->value);

    if((CTC_NPM_IM_FLOW_PROP_DELAY_INTERVAL==p_npm_im_pro->property_type ||CTC_NPM_IM_FLOW_PROP_DELAY==p_npm_im_pro->property_type)
        &&(!p_im_flow_hash->delay_prof_id_valid)
        &&(CTC_NPM_IM_TYPE_MPLS == p_im_flow_hash->type))
    {
        opf.pool_type  = g_npm_master[lchip]->opf_type_im_delay;
        opf.pool_index = 0;
        ret =  sys_usw_opf_alloc_offset(lchip, &opf, 1, &offset);
        if (ret < 0)
        {
            return CTC_E_NO_RESOURCE;
        }
        if (g_npm_master[lchip]->ecpu_npm_im_en && (offset >= SYS_NPM_IM_MAX_DELAY_PROFILE_ECPU))
        {
            sys_usw_opf_free_offset(lchip, &opf, 1, offset);
            return CTC_E_NO_RESOURCE;
        }
        p_im_flow_hash->delay_prof_id= offset;
        p_im_flow_hash->delay_prof_id_valid = 1;
    }

    switch(p_npm_im_pro->property_type)
    {
    case CTC_NPM_IM_FLOW_PROP_DELAY:
        if (SYS_NPM_IM_IS_IP(p_im_flow_hash->type))
        {
            p_im_flow_hash->d_flag = value?1:0;
        }
        else if(CTC_NPM_IM_TYPE_MPLS == p_im_flow_hash->type)
        {
            if (g_npm_master[lchip]->ecpu_npm_im_en)
            {
                ret = CTC_E_INVALID_CONFIG;
                goto error_0;
            }
            cmd = DRV_IOW(IpeAclMplsInBandOamDFlagStatus_t, IpeAclMplsInBandOamDFlagStatus_dFlagStatus_f);
            CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, p_im_flow_hash->delay_prof_id, cmd, &value), ret, error_0);
        }
        break;
    case CTC_NPM_IM_FLOW_PROP_LOSS:
        if (SYS_NPM_IM_IS_IP(p_im_flow_hash->type))
        {
            p_im_flow_hash->l_valid = ((value == CTC_MAX_UINT32_VALUE)?0:1);
            p_im_flow_hash->l_flag = value?1:0;
        }
        else if(CTC_NPM_IM_TYPE_MPLS == p_im_flow_hash->type)
        {
            if (g_npm_master[lchip]->ecpu_npm_im_en)
            {
                ret = CTC_E_INVALID_CONFIG;
                goto error_0;
            }
            if(0 == p_im_flow_hash->loss_prof_id)
            {
                return CTC_E_INVALID_CONFIG;
            }
            cmd = DRV_IOW(IpeAclMplsInBandOamLFlagStatusCtl_t, IpeAclMplsInBandOamLFlagStatusCtl_gLFlagProfile_0_lFlagStatus_f+p_im_flow_hash->loss_prof_id);
            CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, cmd, &value), ret, error_0);
        }
        break;
#if (SDK_WORK_PLATFORM == 0)
#if defined E_UNIT && (FEATURE_MODE == 0)
    case CTC_NPM_IM_FLOW_PROP_DELAY_INTERVAL:
        {
            sys_eunit_npm_im_t ecpu_npm_im;
            sal_memset(&ecpu_npm_im, 0, sizeof(sys_eunit_npm_im_t));
            if (!g_npm_master[lchip]->ecpu_npm_im_en)
            {
                ret = CTC_E_INVALID_CONFIG;
                goto error_0;
            }
            ecpu_npm_im.type = CTC_NPM_IM_FLOW_PROP_DELAY_INTERVAL;
            ecpu_npm_im.profile_id = p_im_flow_hash->delay_prof_id;
            ecpu_npm_im.interval_thrd = value&0x3FF;
            CTC_ERROR_GOTO(_sys_usw_npm_im_set_ecpu(lchip, &ecpu_npm_im), ret, error_0);
        }
        break;
#endif
#endif
    default:
        break;
    }

    return ret;

error_0:
    if(p_im_flow_hash->delay_prof_id_valid)
    {
        sys_usw_opf_free_offset(lchip, &opf, 1, p_im_flow_hash->delay_prof_id);
    }
    return CTC_E_NONE;
}

#if defined E_UNIT && (FEATURE_MODE == 0)
STATIC int32
_sys_usw_npm_im_loss_isr_event(void* bucket_data, void* user_data)
{
    sys_npm_im_flow_hash_t* p_im_flow = (sys_npm_im_flow_hash_t*)bucket_data;
    sys_npm_traverse_im_data_t* p_im_data  = (sys_npm_traverse_im_data_t*)user_data;
    ctc_npm_im_event_t *p_loss_event = p_im_data->p_loss_event;
    ctc_stats_basic_t stats_basic[4];
    sys_stats_param_t sts_param;

    sal_memset(&sts_param, 0, sizeof(sts_param));
    sts_param.id = p_im_flow->stats_id;
    sts_param.flag |= SYS_STATS_FLAG_NPM_OP;
    sts_param.flag |= (p_im_data->loss_color ? SYS_STATS_FLAG_NPM_LOSS : 0);

    if (p_im_flow->loss_prof_id == p_im_data->loss_prof_id)
    {
        p_loss_event->loss_flow[p_loss_event->cnt].flow_id = p_im_flow->flow_id;
        p_loss_event->loss_flow[p_loss_event->cnt].loss_color = p_im_data->loss_color;
        CTC_ERROR_DUMP(sys_usw_flow_stats_get_stats(p_im_data->lchip, &sts_param, stats_basic));
        CTC_ERROR_DUMP(sys_usw_flow_stats_clear_stats(p_im_data->lchip, &sts_param));
        if (p_im_flow->flow_type == 1)
        {
            sal_memcpy(&p_loss_event->loss_flow[p_loss_event->cnt].stats[CTC_INGRESS], &stats_basic[p_im_data->loss_color], sizeof(ctc_stats_basic_t));
        }
        sal_memcpy(&p_loss_event->loss_flow[p_loss_event->cnt].stats[CTC_EGRESS], &stats_basic[2+p_im_data->loss_color], sizeof(ctc_stats_basic_t));
        p_loss_event->cnt++;
    }

    return CTC_E_NONE;
}
#endif

STATIC int32
_sys_usw_npm_im_get_flow_property(uint8 lchip,  ctc_npm_im_flow_property_t* p_npm_im_pro)
{
    uint32 cmd = 0;
    uint32 field_val = 0;
    sys_npm_im_profile_t loss_profile;
    sys_npm_im_flow_hash_t* p_im_flow_hash = NULL;

    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    if (!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NPM_INIT_CHECK(lchip);
    CTC_PTR_VALID_CHECK(p_npm_im_pro);
    CTC_PTR_VALID_CHECK(p_npm_im_pro->value);
    CTC_MAX_VALUE_CHECK(p_npm_im_pro->flow_id, 0xFFFFF);
    sal_memset(&loss_profile,0, sizeof(loss_profile));

    p_im_flow_hash = _sys_usw_npm_ilm_get_im_flow_hash(lchip, p_npm_im_pro->flow_id);
    if(p_im_flow_hash == NULL)
    {
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Flow Id not exist \n");
        return CTC_E_NOT_EXIST;
    }

    switch(p_npm_im_pro->property_type)
    {
    case CTC_NPM_IM_FLOW_PROP_LOSS:
        if (SYS_NPM_IM_IS_IP(p_im_flow_hash->type))
        {
            *(uint32 *)p_npm_im_pro->value = p_im_flow_hash->l_valid?(p_im_flow_hash->l_flag? TRUE: FALSE):FALSE;
        }
        else if (CTC_NPM_IM_TYPE_MPLS == p_im_flow_hash->type)
        {
            cmd = DRV_IOR(IpeAclMplsInBandOamLFlagStatusCtl_t, IpeAclMplsInBandOamLFlagStatusCtl_gLFlagProfile_0_lFlagStatus_f+p_im_flow_hash->loss_prof_id);
            DRV_FIELD_IOCTL(lchip, 0, cmd, &field_val);
            *(uint32 *)p_npm_im_pro->value = field_val? TRUE: FALSE;
        }
        break;
    case CTC_NPM_IM_FLOW_PROP_DELAY:
        if (SYS_NPM_IM_IS_IP(p_im_flow_hash->type))
        {
            *(uint32 *)p_npm_im_pro->value = p_im_flow_hash->d_flag? TRUE: FALSE;
        }
        else if (CTC_NPM_IM_TYPE_MPLS == p_im_flow_hash->type)
        {
            cmd = DRV_IOR(IpeAclMplsInBandOamDFlagStatus_t, IpeAclMplsInBandOamDFlagStatus_dFlagStatus_f);
            DRV_FIELD_IOCTL(lchip, p_im_flow_hash->delay_prof_id, cmd, &field_val);
            *(uint32 *)p_npm_im_pro->value = field_val? TRUE: FALSE;
        }
        break;
#if (SDK_WORK_PLATFORM == 0)
#if defined E_UNIT && (FEATURE_MODE == 0)
    case CTC_NPM_IM_FLOW_PROP_DELAY_INTERVAL:
        {
        uint32 ecpu_db_addr=0;
        uint32 profile_id=0;
        /*read db from ecpu*/
        cmd = DRV_IOR(MiscIntInfo5_t, MiscIntInfo5_miscIntInfo5_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &ecpu_db_addr));
        profile_id = p_im_flow_hash->delay_prof_id;
        profile_id = profile_id>>2;
        profile_id = profile_id<<2;
        drv_usw_chip_read_ext(lchip, ecpu_db_addr+profile_id*4, (uint32*)&loss_profile, 1);
        profile_id = p_im_flow_hash->delay_prof_id;
        drv_usw_chip_read_ext(lchip, ecpu_db_addr+profile_id*4, (uint32*)&loss_profile, 1);
        *(uint32*)p_npm_im_pro->value = loss_profile.interval_thrd;
        }
        break;
#endif
#endif
    default:
        break;
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_npm_im_dump_flow_info_cb(void* bucket_data, void* user_data)
{
    uint16 entry_num = 0;
    sys_npm_im_flow_hash_t* p_im_flow_hash = NULL;
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = ((sys_traverse_t*)user_data)->value1;
#endif
    p_im_flow_hash = (sys_npm_im_flow_hash_t*)bucket_data;
    entry_num = *((uint16*)((sys_traverse_t*)user_data)->data);

    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"%-4d  %-7u  %-9u  %-7u  %-9d  %-15d  %-9d  %-8d  %-7u  %-6u  %-6u  %-8u  %-12u %-9u\n",\
                    entry_num, p_im_flow_hash->flow_id,p_im_flow_hash->flow_type,p_im_flow_hash->type,\
                    p_im_flow_hash->delay_prof_id,p_im_flow_hash->delay_prof_id_valid,p_im_flow_hash->loss_prof_id,\
                    p_im_flow_hash->fih_type,p_im_flow_hash->l_valid,p_im_flow_hash->l_flag,p_im_flow_hash->d_flag,\
                    p_im_flow_hash->stats_id,p_im_flow_hash->acl_entry_id, p_im_flow_hash->acl_bind_en);

    entry_num++;
    *((uint16*)((sys_acl_traverse_data_t*)user_data)->data0) = entry_num;

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_npm_im_cmp_acl_entry_id(void* bucket_data, void* user_data)
{
    uint32 acl_entry_id = 0;
    sys_npm_im_flow_hash_t* p_im_flow_hash = NULL;
    uint8 is_find = 0;

    p_im_flow_hash = (sys_npm_im_flow_hash_t*)bucket_data;
    acl_entry_id = ((sys_traverse_t*)user_data)->value1;

    if (acl_entry_id == p_im_flow_hash->acl_entry_id && (p_im_flow_hash->acl_bind_en))
    {
        ((sys_traverse_t*)user_data)->value2 = p_im_flow_hash->flow_id;
        p_im_flow_hash->acl_entry_id = 0;
        p_im_flow_hash->acl_bind_en = 0;
        is_find = 1;
    }
    return is_find?-1:0;
}

int32
_sys_usw_npm_im_set_ip_en(uint8 lchip, uint32 enable)
{
    int32 ret = 0;
#if defined(ARCTIC)
    uint8 flow_type = 0;
    uint8 ip_type = 0;
    ctc_nh_fp_field_t fp_field;
    ctc_nh_fp_field_t fp_field_list[CTC_NH_FP_FIELD_MAX];
    uint8 fp_field_count = 0;
    ctc_nh_fp_edit_t fp_edit;
    uint16 next_proto_offset = 0;
    uint16 cldr_bitmap_offset = 0;
    uint16 flow_id_offset0 = 0;
    uint16 flow_id_offset1 = 0;
    uint16 l3_proto_offset = 72;
    uint32 l3_proto_val = 0;
    uint8 l3_base_header_len = 0;
    uint8 raw_data[8] = {0};
    uint8 im_header_len = 0;
    uint8 is_ipv6 = 0;
    uint8 is_vxlan = 0;

    if (!DRV_FROM_AT(lchip) || SYS_VCHIP_PP_IS_NOT_BASE(lchip))
    {
        return CTC_E_NONE;
    }

    if ((0 != g_npm_master[lchip]->sink_node_fp_id[0] && enable) ||
        (0 == g_npm_master[lchip]->sink_node_fp_id[0] && !enable))
    {
        return CTC_E_NONE;
    }

    if(g_npm_master[lchip]->p_npm_im_flow_hash->count)
    {
        return CTC_E_IN_USE;
    }

    /*Step2:add nh fp, creat fp id for ipv4 ioam and ipv6 ioam*/
    for(flow_type = CTC_NPM_IM_FLOW_TYPE_SOURCE; flow_type < CTC_NPM_IM_FLOW_TYPE_MAX; flow_type++)
    {
        if (CTC_NPM_IM_FLOW_TYPE_TRANSIT == flow_type)
        {
            continue;
        }
        for(ip_type = SYS_IM_TYPE_IPV4; ip_type < SYS_IM_MAX_TYPE; ip_type++)
        {
            if (0 ==  enable)
            {
                if (CTC_NPM_IM_FLOW_TYPE_SOURCE == flow_type)
                {
                    sys_usw_nh_remove_fp(lchip, g_npm_master[lchip]->src_node_fp_id[ip_type]);
                    g_npm_master[lchip]->src_node_fp_id[ip_type] = 0;
                    sys_usw_nh_remove_fp(lchip, g_npm_master[lchip]->src_node_delay_fp_id[ip_type]);
                    g_npm_master[lchip]->src_node_delay_fp_id[ip_type] = 0; 
                }
                else
                {
                    sys_usw_nh_remove_fp(lchip, g_npm_master[lchip]->sink_node_fp_id[ip_type]);
                    g_npm_master[lchip]->sink_node_fp_id[ip_type] = 0;
                }
                continue;
            }
            sal_memset(&fp_field_list, 0, sizeof(fp_field_list));
            fp_field_count = 0;
            is_ipv6 = ((SYS_IM_TYPE_IPV4 == ip_type) || (SYS_IM_TYPE_VXLAN_IPV4 == ip_type)) ? 0:1;
            is_vxlan = ((SYS_IM_TYPE_VXLAN_IPV4 == ip_type) || (SYS_IM_TYPE_VXLAN_IPV6 == ip_type)) ? 1:0;
            if (CTC_NPM_IM_FLOW_TYPE_SOURCE == flow_type)
            {
                /*2.1 source node config insert im flow header, ipv4 4bytes ipv6 8 bytes*/
                next_proto_offset = is_ipv6?0:24;
                cldr_bitmap_offset = is_ipv6?52:20;
                flow_id_offset0 = is_ipv6?32:0;
                flow_id_offset1 = is_ipv6?48:16;
                l3_proto_offset = is_ipv6?48:72;
                l3_proto_val = is_ipv6?0x00: g_npm_master[lchip]->im_protocol;
                l3_base_header_len = is_ipv6?40:20;
                im_header_len = is_ipv6?8:4;
                if (is_ipv6)
                {
                    raw_data[0] = 0x00;
                    raw_data[1] = 0x00;
                    raw_data[2] = g_npm_master[lchip]->im_protocol;
                    raw_data[3] = 0x04;
                }

                sal_memset(&fp_field, 0, sizeof(fp_field));
                /*2.1.1 get l3 protocol from packet, and put it in xedit data(ioam header)*/
                fp_field.offset = next_proto_offset;
                fp_field.len = 8;
                fp_field.data.type = (ip_type >SYS_IM_TYPE_IPV6)?CTC_NH_FP_DATA_RAW:CTC_NH_FP_DATA_L3_PROTOCOL;
                fp_field.data.len = (ip_type >SYS_IM_TYPE_IPV6)?16:8;
                fp_field.zone = CTC_NH_FP_ZONE_INS_DATA;
                fp_field.data.value = 17;
                fp_field.data_op = (ip_type >SYS_IM_TYPE_IPV6)?CTC_NH_FP_OP_SHL:0;
                sal_memcpy(&fp_field_list[fp_field_count++], &fp_field, sizeof(fp_field));

                /*2.1.2 get cldr bitmap from xdata[20], and put it in xedit data(ioam header)*/
                sal_memset(&fp_field, 0, sizeof(fp_field));
                fp_field.offset = cldr_bitmap_offset;
                fp_field.len = 4;
                fp_field.data.type = CTC_NH_FP_DATA_XDATA;
                fp_field.data.src_offset = 20;
                fp_field.data.len = 4;
                /*fp_field.data.mask = 0x30;
                fp_field.data.shift = 2;
                fp_field.data_op = CTC_NH_FP_OP_ADD;
                fp_field.data_r.type = CTC_NH_FP_DATA_XDATA;
                fp_field.data_r.src_offset = 24;
                fp_field.data_r.len = 4;
                fp_field.result_shift = 2;*/
                fp_field.zone = CTC_NH_FP_ZONE_INS_DATA;
                sal_memcpy(&fp_field_list[fp_field_count++], &fp_field, sizeof(fp_field));

                /*2.1.3 get flow id from xdata, and put it in xedit data(ioam header)*/
                sal_memset(&fp_field, 0, sizeof(fp_field));
                fp_field.offset = flow_id_offset1;
                fp_field.len = 4;
                fp_field.data.type = CTC_NH_FP_DATA_XDATA;
                fp_field.data.src_offset = 16;
                fp_field.data.len = 4;
                fp_field.zone = CTC_NH_FP_ZONE_INS_DATA;
                sal_memcpy(&fp_field_list[fp_field_count++], &fp_field, sizeof(fp_field));

                sal_memset(&fp_field, 0, sizeof(fp_field));
                fp_field.offset = flow_id_offset0;
                fp_field.len = 16;
                fp_field.data.type = CTC_NH_FP_DATA_XDATA;
                fp_field.data.src_offset = 0;
                fp_field.data.len = 16;
                fp_field.zone = CTC_NH_FP_ZONE_INS_DATA;
                sal_memcpy(&fp_field_list[fp_field_count++], &fp_field, sizeof(fp_field));

                /*2.1.4 zone 0 edit l3 protocol in packet*/
                sal_memset(&fp_field, 0, sizeof(fp_field));
                fp_field.offset = l3_proto_offset;
                fp_field.len = 8;
                fp_field.data.type = CTC_NH_FP_DATA_RAW;
                fp_field.data.value = l3_proto_val;
                fp_field.data.len = 8;
                sal_memcpy(&fp_field_list[fp_field_count++], &fp_field, sizeof(fp_field));

                /*2.1.5 process xedit*/
                sal_memset(&fp_edit, 0, sizeof(fp_edit));
                fp_edit.fp_id = 0;
                fp_edit.edit_type = CTC_NH_FP_EDIT_INS;
                fp_edit.offset_type = CTC_PKT_OFFSET_L3;
                fp_edit.offset = l3_base_header_len;
                fp_edit.len = im_header_len;
                fp_edit.data = raw_data;
                if (!is_ipv6)
                {
                    fp_edit.l3chksum.enable = 1;
                    fp_edit.l3chksum.offset = 10;
                    fp_edit.l3chksum.mask = 0x0040;
                }

                CTC_SET_FLAG(fp_edit.flag, CTC_NH_FP_FLAG_STAGE2);
                CTC_SET_FLAG(fp_edit.flag, CTC_NH_FP_FLAG_REP_SEL_VALID);
                fp_edit.replace_sel = is_vxlan?3:2;
                fp_edit.use_outer = is_vxlan?1:0;
                fp_edit.field_cnt = fp_field_count;
                fp_edit.p_field_list = fp_field_list;
                CTC_ERROR_GOTO(sys_usw_nh_add_fp(lchip, &fp_edit, 1), ret, error_proc1);
                /*2.1.6 store fp_id*/
                g_npm_master[lchip]->src_node_fp_id[ip_type] = fp_edit.fp_id;

                fp_field_list[1].data.mask = 0x30;
                fp_field_list[1].data.shift = 2;
                fp_field_list[1].data_op = CTC_NH_FP_OP_ADD;
                fp_field_list[1].data_r.type = CTC_NH_FP_DATA_XDATA;
                fp_field_list[1].data_r.src_offset = 24;
                fp_field_list[1].data_r.len = 4;
                fp_field_list[1].result_shift = 2;
                fp_field_list[1].zone = CTC_NH_FP_ZONE_INS_DATA;
                fp_edit.fp_id = 0;
                CTC_ERROR_GOTO(sys_usw_nh_add_fp(lchip, &fp_edit, 1), ret, error_proc1);
                g_npm_master[lchip]->src_node_delay_fp_id[ip_type] = fp_edit.fp_id;

            }
            else
            {
                if(1 == is_vxlan)
                {
                    continue;
                }
                /*2.2 sink node config delete im flow header, ipv4 4bytes ipv6 8 bytes*/
                l3_proto_offset = ip_type?48:72;
                l3_base_header_len = ip_type?40:20;
                im_header_len = ip_type?8:4;
                
                /*2.2.1 recovery l3 protocol*/
                sal_memset(&fp_field, 0, sizeof(fp_field));
                fp_field.offset = l3_proto_offset;
                fp_field.len = 8;
                fp_field.data.type = CTC_NH_FP_DATA_L3_PROTOCOL;
                fp_field.data.len = 8;
                sal_memcpy(&fp_field_list[fp_field_count++], &fp_field, sizeof(fp_field));

                /*2.2.2 process xedit*/
                sal_memset(&fp_edit, 0, sizeof(fp_edit));
                fp_edit.fp_id = 0;
                fp_edit.edit_type = CTC_NH_FP_EDIT_DEL;
                fp_edit.offset_type = CTC_PKT_OFFSET_L3;
                fp_edit.offset = l3_base_header_len;
                fp_edit.len = im_header_len;
                if (!is_ipv6)
                {
                    fp_edit.l3chksum.enable = 1;
                    fp_edit.l3chksum.offset = 0xff;
                }
                fp_edit.field_cnt = fp_field_count;
                fp_edit.p_field_list = fp_field_list;
                CTC_SET_FLAG(fp_edit.flag, CTC_NH_FP_FLAG_STAGE2);
                CTC_ERROR_GOTO(sys_usw_nh_add_fp(lchip, &fp_edit, 1), ret, error_proc1);
                /*2.2.3 store fp_id*/
                g_npm_master[lchip]->sink_node_fp_id[ip_type] = fp_edit.fp_id;
            }
        }
    }

    return CTC_E_NONE;
error_proc1:
    if (enable)
    {
        for(flow_type = CTC_NPM_IM_FLOW_TYPE_SOURCE; flow_type < CTC_NPM_IM_FLOW_TYPE_MAX; flow_type++)
        {
            if (CTC_NPM_IM_FLOW_TYPE_TRANSIT == flow_type)
            {
                continue;
            }
            for(ip_type = SYS_IM_TYPE_IPV4; ip_type < SYS_IM_MAX_TYPE; ip_type++)
            {
                if (CTC_NPM_IM_FLOW_TYPE_SOURCE == flow_type)
                {
                    sys_usw_nh_remove_fp(lchip, g_npm_master[lchip]->src_node_fp_id[ip_type]);
                    g_npm_master[lchip]->src_node_fp_id[ip_type] = 0;
                    sys_usw_nh_remove_fp(lchip, g_npm_master[lchip]->src_node_delay_fp_id[ip_type]);
                    g_npm_master[lchip]->src_node_delay_fp_id[ip_type] = 0;
                }
                else
                {
                    sys_usw_nh_remove_fp(lchip, g_npm_master[lchip]->sink_node_fp_id[ip_type]);
                    g_npm_master[lchip]->sink_node_fp_id[ip_type] = 0;
                }
            }
        }
    }
#endif
    return ret;
}

int32
_sys_usw_npm_im_set_mpls_en(uint8 lchip, uint32 enable)
{
    uint32 start_offset = 0;
    uint32 entry_num = 0;
    sys_usw_opf_t opf;
    int32 ret = CTC_E_NONE;

    if (enable && (!g_npm_master[lchip]->loss_flow))
    {
        /*Loss profile_id opf*/
        CTC_ERROR_GOTO(sys_usw_opf_init(lchip, &g_npm_master[lchip]->opf_type_im_loss, 1, "opf-npm-type-im-flow"), ret, error_proc1);
        opf.pool_type  = g_npm_master[lchip]->opf_type_im_loss;
        opf.pool_index = 0;
        start_offset = (1<<DRV_ENUM(DRV_KEY_METADATA_BITS))-1-2*SYS_NPM_IM_MAX_SESSION ;
        entry_num = 2*SYS_NPM_IM_MAX_SESSION;
        CTC_ERROR_GOTO(sys_usw_opf_init_offset(lchip, &opf, start_offset, entry_num), ret, error_proc);

        g_npm_master[lchip]->loss_flow = mem_malloc(MEM_NPM_MODULE, sizeof(ctc_npm_im_loss_t)*SYS_NPM_IM_MAX_SESSION);
        if(!g_npm_master[lchip]->loss_flow)
        {
            SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [NPM] No Memory \n");
            goto error_proc;
        }
    }
    else if (!enable && g_npm_master[lchip]->loss_flow)
    {
        opf.pool_type  = g_npm_master[lchip]->opf_type_im_loss;
        opf.pool_index = 0;
        if(g_npm_master[lchip]->p_npm_im_flow_hash->count)
        {
            ret = CTC_E_IN_USE;
            goto  error_proc1;
        }
        mem_free(g_npm_master[lchip]->loss_flow);
        g_npm_master[lchip]->loss_flow = NULL;

        sys_usw_opf_deinit(lchip, g_npm_master[lchip]->opf_type_im_loss);
        g_npm_master[lchip]->opf_type_im_loss = 0;
    }
    else
    {
        return CTC_E_INVALID_PARAM;
    }

    CTC_ERROR_GOTO(SYS_CB(SYS_CB_IPFIX_DFT_CFG_TO_NPM, lchip, enable), ret, error_proc_2);
    return CTC_E_NONE;
error_proc_2:
    if (g_npm_master[lchip]->loss_flow)
    {
        mem_free(g_npm_master[lchip]->loss_flow);
        g_npm_master[lchip]->loss_flow = NULL;
    }
error_proc:
    sys_usw_opf_deinit(lchip, g_npm_master[lchip]->opf_type_im_loss);
    g_npm_master[lchip]->opf_type_im_loss = 0;
error_proc1:
    return ret;
}

#define ______API______
int32
sys_usw_npm_im_set_flow_en(uint8 lchip, uint32 type, uint32 enable)
{
    int32 ret = CTC_E_NONE;

    SYS_NPM_INIT_CHECK(lchip);
    if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }

    NPM_LOCK(lchip);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NPM, SYS_WB_APPID_NPM_SUBID_MASTER, 1);
    if (SYS_NPM_IM_IS_IP(type))
    {
        ret = _sys_usw_npm_im_set_ip_en(lchip, enable);
    }
    else if (CTC_NPM_IM_TYPE_MPLS == type)
    {
        ret = _sys_usw_npm_im_set_mpls_en(lchip, enable);
    }
    NPM_UNLOCK(lchip);

    return ret;
}

int32
sys_usw_npm_im_get_flow_en(uint8 lchip, uint32 type, uint32* enable)
{
    SYS_NPM_INIT_CHECK(lchip);
    CTC_PTR_VALID_CHECK(enable);
    NPM_LOCK(lchip);
    if (SYS_NPM_IM_IS_IP(type))
    {
        *enable = g_npm_master[lchip]->src_node_fp_id[0]?1:0;
    }
    else if (CTC_NPM_IM_TYPE_MPLS == type)
    {
        *enable = g_npm_master[lchip]->loss_flow?1:0;
    }
    NPM_UNLOCK(lchip);
    return CTC_E_NONE;
}

int32
sys_usw_npm_im_get_flow_id_with_metadata(uint8 lchip, uint16 metadata, uint32* p_flow_id)
{
    sys_traverse_t user_data;
    int32 ret = CTC_E_NONE;

    sal_memset(&user_data, 0, sizeof(user_data));
    NPM_LOCK(lchip);
    user_data.value1 = metadata;
    ret = ctc_hash_traverse(g_npm_master[lchip]->p_npm_im_flow_hash, _sys_usw_npm_im_cmp_metadata, (void*) (&user_data));
    if (ret)
    {
        *p_flow_id = user_data.value2;
    }
    NPM_UNLOCK(lchip);
    return ret?CTC_E_NONE:CTC_E_NOT_EXIST;
}

int32
sys_usw_npm_im_set_loss_profile_interval(uint8 lchip, void*p_loss_prof)
{
    int32 ret = CTC_E_NONE;
#if (SDK_WORK_PLATFORM == 0)
#if defined E_UNIT && (FEATURE_MODE == 0)
    ctc_npm_im_loss_prof_t* p_loss_prof_tmp = (ctc_npm_im_loss_prof_t*)p_loss_prof;
    uint32 cmd = 0;
    uint32 value = 0;
    sys_eunit_npm_im_t ecpu_npm_im;
    SYS_NPM_INIT_CHECK(lchip);
    if (!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    sal_memset(&ecpu_npm_im, 0, sizeof(sys_eunit_npm_im_t));
    CTC_MIN_VALUE_CHECK(p_loss_prof_tmp->loss_prof_id, 1);
    CTC_MAX_VALUE_CHECK(p_loss_prof_tmp->loss_prof_id, 7);
    NPM_LOCK(lchip);
    cmd = DRV_IOR(ParserMplsCtl_t, ParserMplsCtl_supportMplsInbandOam_f);
    CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, cmd, &value), ret, roll_back_0);
    if (!value)
    {
        NPM_UNLOCK(lchip);
        return CTC_E_INVALID_CONFIG;
    }
    ecpu_npm_im.type = CTC_NPM_IM_FLOW_PROP_LOSS_INTERVAL;
    ecpu_npm_im.profile_id = p_loss_prof_tmp->loss_prof_id;
    ecpu_npm_im.interval_thrd = p_loss_prof_tmp->interval&0x3FF;
    CTC_ERROR_GOTO(_sys_usw_npm_im_set_ecpu(lchip, &ecpu_npm_im), ret, roll_back_0);
roll_back_0:
    NPM_UNLOCK(lchip);
#endif
#endif
    return ret;
}

int32
sys_usw_npm_im_get_loss_profile_interval(uint8 lchip, void*p_loss_prof)
{
    int32 ret = CTC_E_NONE;
#if (SDK_WORK_PLATFORM == 0)
#if defined E_UNIT && (FEATURE_MODE == 0)
    ctc_npm_im_loss_prof_t* p_loss_prof_tmp = (ctc_npm_im_loss_prof_t*)p_loss_prof;
    uint32 ecpu_db_addr=0;
    uint32 profile_id=0;
    sys_npm_im_profile_t loss_profile;
    uint32 cmd = 0;
    SYS_NPM_INIT_CHECK(lchip);
    CTC_MIN_VALUE_CHECK(p_loss_prof_tmp->loss_prof_id, 1);
    CTC_MAX_VALUE_CHECK(p_loss_prof_tmp->loss_prof_id, 7);
    if (!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    /*read db from ecpu*/
    NPM_LOCK(lchip);
    cmd = DRV_IOR(MiscIntInfo5_t, MiscIntInfo5_miscIntInfo5_f);
    CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, cmd, &ecpu_db_addr), ret, roll_back_0);
    profile_id = (p_loss_prof_tmp->loss_prof_id +SYS_NPM_IM_MAX_DELAY_PROFILE_ECPU-1);
    profile_id = profile_id>>2;
    profile_id = profile_id<<2;
    drv_usw_chip_read_ext(lchip, ecpu_db_addr+profile_id*4, (uint32*)&loss_profile, 1);
    profile_id = (p_loss_prof_tmp->loss_prof_id +SYS_NPM_IM_MAX_DELAY_PROFILE_ECPU-1);
    drv_usw_chip_read_ext(lchip, ecpu_db_addr+profile_id*4, (uint32*)&loss_profile, 1);
    p_loss_prof_tmp->interval = loss_profile.interval_thrd;
roll_back_0:
    NPM_UNLOCK(lchip);
#endif
#endif
    return ret;
}

int32
sys_usw_npm_im_convert_flow_id(uint8 lchip, uint32 flow_id, uint32* flow_id_converted)
{
    if(!DRV_FROM_AT(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }

    CTC_PTR_VALID_CHECK(flow_id_converted);
    CTC_MAX_VALUE_CHECK(flow_id, 0xFFFFF);
    
    /*true value stores in xedit container as |4bit|8bit|4bit(the second)| format*/
    /*the converted value must store in xdata as |4bit(the second)|4bit|8bit| format*/
    //*flow_id_converted = (flow_id&0xf0000) | ((flow_id & 0xf) << 12) | (((flow_id >> 12) & 0xf) << 8) | ((flow_id >> 4) & 0xff);

    *flow_id_converted = (((flow_id&0xffff0)>>4) | ((flow_id&0xf) <<16));

    return CTC_E_NONE;
}

int32
sys_usw_npm_im_recovery_flow_id(uint8 lchip, uint32 flow_id_converted, uint32* flow_id)
{
    if(!DRV_FROM_AT(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }

    CTC_PTR_VALID_CHECK(flow_id);
    CTC_MAX_VALUE_CHECK(flow_id_converted, 0xFFFFF);
    
    /*true value stores in xedit container or xph as |4bit|8bit|4bit(the second)| format*/
    /*the converted value must store in xdata as |4bit(the second)|4bit|8bit| format*/
    //*flow_id = (flow_id_converted&0xf0000) | (((flow_id_converted >> 8) & 0xf) << 12)| ((flow_id_converted & 0xff) << 4) | ((flow_id_converted >> 12) & 0xf);

    *flow_id = (((flow_id_converted&0xffff)<<4) | ((flow_id_converted&0xf0000) >>16));
    return CTC_E_NONE;
}

int32
sys_usw_npm_im_create_flow(uint8 lchip, ctc_npm_im_flow_t* p_flow)
{
    int32 ret = CTC_E_NONE;
    sys_npm_im_flow_hash_t* p_im_flow_hash = NULL;
    uint32 offset = 0;
    sys_usw_opf_t   opf;
    sys_stats_param_t sts_param;
    uint32 igs_stats_ptr = 0;
    uint32 egs_stats_ptr = 0;

    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    if (!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NPM_INIT_CHECK(lchip);
    CTC_PTR_VALID_CHECK(p_flow);
    CTC_MAX_VALUE_CHECK(p_flow->flow_id, 0xFFFFF);
    if(SYS_NPM_IM_IS_IP(p_flow->type))
    {
        CTC_MAX_VALUE_CHECK(p_flow->flow_type, CTC_NPM_IM_FLOW_TYPE_SINK);
    }
    else if (CTC_NPM_IM_TYPE_MPLS == p_flow->type)
    {
        CTC_MAX_VALUE_CHECK(p_flow->flow_type, 1);
        CTC_MAX_VALUE_CHECK(p_flow->fih_type, 0x02);

        if((CTC_NPM_IM_FLOW_TYPE_SOURCE == p_flow->flow_type))  /* flow type, 0: Source Node */
        {
            CTC_MIN_VALUE_CHECK(p_flow->loss_prof_id, 1);
            CTC_MAX_VALUE_CHECK(p_flow->loss_prof_id, 7);
        }
    }

    if (g_npm_master[lchip]->p_npm_im_flow_hash && (SYS_NPM_IM_MAX_SESSION == g_npm_master[lchip]->p_npm_im_flow_hash->count))
    {
        return CTC_E_NO_RESOURCE;
    }
    
    if(p_flow->stats_id) /* Loss Measurement use stats, and stats_id 0 is invalid, jude stats exist or not */
    {
        sal_memset(&sts_param, 0, sizeof(sts_param));
        sts_param.id = p_flow->stats_id;
        sts_param.type = SYS_STATS_TYPE_NPM_IM;

        sts_param.dir = CTC_EGRESS;
        sts_param.num = 2;
        CTC_ERROR_RETURN(sys_usw_flow_stats_alloc_statsptr(lchip, &sts_param));
        egs_stats_ptr = sts_param.ptr;

        if (SYS_NPM_IM_IS_IP(p_flow->type))
        {
            sts_param.dir = CTC_INGRESS;
            CTC_ERROR_GOTO(sys_usw_flow_stats_alloc_statsptr(lchip, &sts_param), ret, error0);
            igs_stats_ptr = sts_param.ptr;
        }
        else if (CTC_NPM_IM_TYPE_MPLS == p_flow->type)
        {
            if (p_flow->flow_type)
            {
                sts_param.dir = CTC_INGRESS;
                CTC_ERROR_GOTO(sys_usw_flow_stats_alloc_statsptr(lchip, &sts_param), ret, error0);
                igs_stats_ptr = sts_param.ptr;
            }
        }
        
    }

    NPM_LOCK(lchip);
    if ((0 == g_npm_master[lchip]->loss_flow) && (0 == g_npm_master[lchip]->src_node_fp_id[0]))
    {
        ret = CTC_E_NOT_INIT;
        goto error1;
    }
    p_im_flow_hash = _sys_usw_npm_ilm_get_im_flow_hash(lchip,p_flow->flow_id);
    if(p_im_flow_hash == NULL)
    {
        p_im_flow_hash = mem_malloc(MEM_NPM_MODULE, sizeof(sys_npm_im_flow_hash_t));
        if(!p_im_flow_hash)
        {
            SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [NPM] No Memory \n");
            ret = CTC_E_NO_MEMORY;
            goto error1;
        }
        sal_memset(p_im_flow_hash,0,sizeof(sys_npm_im_flow_hash_t));

        p_im_flow_hash->flow_id = p_flow->flow_id;
        p_im_flow_hash->type = p_flow->type;
        p_im_flow_hash->flow_type = p_flow->flow_type;
        p_im_flow_hash->loss_prof_id = p_flow->loss_prof_id;
        p_im_flow_hash->fih_type = p_flow->fih_type;
        p_im_flow_hash->stats_id = p_flow->stats_id;
        p_im_flow_hash->igs_stats_ptr = igs_stats_ptr;
        p_im_flow_hash->egs_stats_ptr = egs_stats_ptr;

        if ((CTC_NPM_IM_TYPE_MPLS == p_flow->type) && (p_flow->flow_type))
        {
            sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
            opf.pool_type  = g_npm_master[lchip]->opf_type_im_loss;
            opf.pool_index = 0;
            CTC_ERROR_GOTO(sys_usw_opf_alloc_offset(lchip, &opf, 2, &offset), ret, error2);
            p_im_flow_hash->metadata = offset;
        }
    }
    else
    {
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Flow Id Exist \n");
        NPM_UNLOCK(lchip);
        return CTC_E_ENTRY_EXIST;
    }
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NPM, SYS_WB_APPID_NPM_SUBID_IM_FLOW_HASH, 1);
    CTC_ERROR_GOTO(_sys_usw_npm_im_flow_add_hash(lchip, p_im_flow_hash), ret, error3);
    NPM_UNLOCK(lchip);
    return CTC_E_NONE;

error3:
    if ((CTC_NPM_IM_TYPE_MPLS == p_flow->type) && (p_flow->flow_type))
    {
        opf.pool_type  = g_npm_master[lchip]->opf_type_im_loss;
        opf.pool_index = 0;
        sys_usw_opf_free_offset(lchip, &opf, 2, p_im_flow_hash->metadata);
    }
error2:
    mem_free(p_im_flow_hash);
error1:
    NPM_UNLOCK(lchip);
    if(p_flow->stats_id)
    {
        sts_param.dir = CTC_INGRESS;
        sts_param.ptr = 0;
        sys_usw_flow_stats_free_statsptr(lchip, &sts_param);
    }
error0:
    if(p_flow->stats_id)
    {
        sts_param.dir = CTC_EGRESS;
        sts_param.ptr = 0;
        sys_usw_flow_stats_free_statsptr(lchip, &sts_param);
    }
    
    return ret;
}

int32
sys_usw_npm_im_destory_flow(uint8 lchip, uint32 flow_id)
{
    sys_usw_opf_t   opf;
    sys_npm_im_flow_hash_t* p_im_flow_hash = NULL;
    sys_stats_param_t sts_param;
    if (!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NPM_INIT_CHECK(lchip);
    CTC_MAX_VALUE_CHECK(flow_id, 0xFFFFF);

    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));

    NPM_LOCK(lchip);
    p_im_flow_hash = _sys_usw_npm_ilm_get_im_flow_hash(lchip, flow_id);
    if(p_im_flow_hash == NULL)
    {
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Flow Id not exist \n");
        NPM_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NPM, SYS_WB_APPID_NPM_SUBID_IM_FLOW_HASH, 1);
    /* free opf */
    if(p_im_flow_hash->delay_prof_id_valid)
    {
        opf.pool_type  = g_npm_master[lchip]->opf_type_im_delay;
        opf.pool_index = 0;
        sys_usw_opf_free_offset(lchip, &opf, 1, p_im_flow_hash->delay_prof_id);
    }
    
    sal_memset(&sts_param, 0, sizeof(sts_param));
    sts_param.id = p_im_flow_hash->stats_id;
    sts_param.type = SYS_STATS_TYPE_NPM_IM;

    if (CTC_NPM_IM_TYPE_MPLS == p_im_flow_hash->type)
    {
        sts_param.dir = CTC_EGRESS;
        sts_param.num = 2;
        sys_usw_flow_stats_free_statsptr(lchip, &sts_param);

        /* free metadata*/
        if (p_im_flow_hash->flow_type)
        {
            opf.pool_type  = g_npm_master[lchip]->opf_type_im_loss;
            opf.pool_index = 0;
            sys_usw_opf_free_offset(lchip, &opf, 2, p_im_flow_hash->metadata);

            sts_param.dir = CTC_INGRESS;
            sys_usw_flow_stats_free_statsptr(lchip, &sts_param);
        }
    }
    else if (SYS_NPM_IM_IS_IP(p_im_flow_hash->type))
    {
        sts_param.dir = CTC_EGRESS;
        sts_param.num = 4;
        sys_usw_flow_stats_free_statsptr(lchip, &sts_param);

        sts_param.dir = CTC_INGRESS;
        sys_usw_flow_stats_free_statsptr(lchip, &sts_param);
    }
    
    /* free hash */
    _sys_usw_npm_im_flow_remove_hash(lchip, p_im_flow_hash);
    NPM_UNLOCK(lchip);

    return CTC_E_NONE;
}

int32
sys_usw_npm_im_set_flow_property(uint8 lchip, ctc_npm_im_flow_property_t* p_npm_im_pro)
{
    int32 ret = CTC_E_NONE;
    sys_npm_im_flow_hash_t* p_im_flow_hash = NULL;
    ctc_acl_field_action_t act_field;
    uint8 flow_type = 0;
    uint32 acl_entry_id = 0;
    uint8 type = 0;
    uint8 acl_bind_en = 0;
    SYS_NPM_INIT_CHECK(lchip);

    NPM_LOCK(lchip);
    p_im_flow_hash = _sys_usw_npm_ilm_get_im_flow_hash(lchip, p_npm_im_pro->flow_id);
    if(NULL == p_im_flow_hash)
    {
        NPM_UNLOCK(lchip);
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Flow Id not exist \n");
        return CTC_E_NOT_EXIST;
    }

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NPM, SYS_WB_APPID_NPM_SUBID_IM_FLOW_HASH, 1);
    ret = _sys_usw_npm_im_set_flow_property(lchip,p_npm_im_pro, p_im_flow_hash);
    if (CTC_E_NONE == ret)
    {
        flow_type = p_im_flow_hash->flow_type;
        type = p_im_flow_hash->type;
        acl_entry_id = p_im_flow_hash->acl_entry_id;
        acl_bind_en = p_im_flow_hash->acl_bind_en;
    }
    NPM_UNLOCK(lchip);

    /*prevent deadly embrace, for arctic ip ioam, npm calls iacl action interface, while iacl action calls npm at the same time;*/
    if (acl_bind_en && (SYS_NPM_IM_IS_IP(type)) && (CTC_NPM_IM_FLOW_TYPE_SOURCE == flow_type))
    {
        uint8 lchip_start = 0,lchip_end = 0,all_chip = 1;
        uint16  pp_bmp = 0xffff;
        sal_memset(&act_field, 0, sizeof(act_field));
        act_field.type = CTC_ACL_FIELD_ACTION_NPM_IM_FLOW_ID;
        act_field.data0 = p_npm_im_pro->flow_id;

        if(MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_ACL))
        {
            CTC_ERROR_RETURN(sys_usw_acl_lookup_entry_hash(lchip, acl_entry_id, SYS_COM_ENTRY_HASH_ACL_ENTRY, &pp_bmp));
        }

        CTC_AT_FOREACH_LCHIP2(lchip_start,lchip_end,all_chip,CTC_FEATURE_ACL)
        {
            if (!CTC_IS_BIT_SET(pp_bmp, lchip-lchip_start))
            {
                continue;
            }
            CTC_ERROR_RETURN(sys_usw_acl_add_action_field(lchip, acl_entry_id, &act_field));
        }
    }
    return ret;
}

#if defined E_UNIT && (FEATURE_MODE == 0)
int32
sys_usw_npm_im_event_cb(uint8 gchip, void* data)
{
    ctc_npm_im_event_t* event = data;
    uint16 index = 0;
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = 0;
    CTC_ERROR_RETURN(sys_usw_get_local_chip_id(gchip, &lchip));
#endif
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    CTC_PTR_VALID_CHECK(data);
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Loss Flow count :%d\n", event->cnt);
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n----------------------------Loss Color Switch Event Occur--------------------------\n");
    for(index=0;index<event->cnt;index++)
    {
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Loss Flow id     :%d\n", event->loss_flow[index].flow_id);
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Loss Color       :%d\n", event->loss_flow[index].loss_color);
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Ingress  packets: %"PRIu64", bytes: %"PRIu64"\n", event->loss_flow[index].stats[CTC_INGRESS].packet_count, event->loss_flow[index].stats[CTC_INGRESS].byte_count);
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Egress   packets: %"PRIu64", bytes: %"PRIu64"\n", event->loss_flow[index].stats[CTC_EGRESS].packet_count, event->loss_flow[index].stats[CTC_EGRESS].byte_count);
    }
    return CTC_E_NONE;
}

int32
sys_usw_npm_im_loss_isr(uint8 lchip, uint8 isr_type, void* p_data)
{
    sys_usw_eunit_isr_data_t* isr_data = (sys_usw_eunit_isr_data_t*)p_data;
    CTC_INTERRUPT_EVENT_FUNC npm_im_cb = NULL;
    sys_npm_traverse_im_data_t im_data;
    ctc_npm_im_event_t loss_event;
    sys_npm_im_profile_t loss_profile[SYS_NPM_IM_MAX_LOSS_PROFILE];
    uint8 gchip = 0;
    uint32 addr_loss_profile=0;
    uint32 cmd = 0;
    uint8 chan_en = 0;
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "Intr id is %d\n", isr_data->irq_id);
    SYS_NPM_INIT_CHECK(lchip);
    CTC_MIN_VALUE_CHECK(isr_data->irq_id, SYS_NPM_IRQ_NPM_IM_LOSS_PROFILE1);
    CTC_MAX_VALUE_CHECK(isr_data->irq_id, SYS_NPM_IRQ_NPM_IM_LOSS_PROFILE1+SYS_NPM_IM_MAX_LOSS_PROFILE-1);
    sal_memset(&loss_event, 0, sizeof(ctc_npm_im_event_t));
    sal_memset(&loss_profile, 0, sizeof(loss_profile));
    sal_memset(&im_data, 0, sizeof(sys_npm_traverse_im_data_t));

    sys_usw_dma_get_chan_en(lchip, SYS_DMA_FLOW_STATS_CHAN_ID, &chan_en);
    CTC_ERROR_RETURN(sys_usw_interrupt_get_event_cb(lchip, CTC_EVENT_NPM_IM, &npm_im_cb));
    if (!npm_im_cb || !g_npm_master[lchip]->loss_flow || !chan_en)
    {
        return CTC_E_NOT_INIT;
    }
    CTC_ERROR_RETURN(sys_usw_get_gchip_id(lchip, &gchip));

    /*read db from ecpu*/
    NPM_LOCK(lchip);
    cmd = DRV_IOR(MiscIntInfo5_t, MiscIntInfo5_miscIntInfo5_f);
    DRV_FIELD_IOCTL(lchip, 0, cmd, &addr_loss_profile);
    drv_usw_chip_read_ext(lchip, addr_loss_profile+(4*SYS_NPM_IM_MAX_DELAY_PROFILE_ECPU), (uint32*)loss_profile, 7);

    sal_memset(g_npm_master[lchip]->loss_flow, 0, sizeof(ctc_npm_im_loss_t)*SYS_NPM_IM_MAX_SESSION);
    im_data.loss_prof_id = isr_data->irq_id - SYS_NPM_IRQ_NPM_IM_LOSS_PROFILE1 + 1;
    im_data.loss_color = !loss_profile[isr_data->irq_id - SYS_NPM_IRQ_NPM_IM_LOSS_PROFILE1].loss_color;
    loss_event.loss_flow = g_npm_master[lchip]->loss_flow;
    im_data.p_loss_event = &loss_event;
    im_data.lchip = lchip;
    ctc_hash_traverse(g_npm_master[lchip]->p_npm_im_flow_hash, _sys_usw_npm_im_loss_isr_event, (void*)(&im_data));
    NPM_UNLOCK(lchip);

    npm_im_cb(gchip,&loss_event);

    return CTC_E_NONE;
}

int32
sys_usw_npm_im_set_ecpu_en(uint8 lchip, uint32 value)
{
    int32 ret = CTC_E_NONE;
    sys_eunit_npm_im_t ecpu_npm_im;
    sal_memset(&ecpu_npm_im, 0,sizeof(sys_eunit_npm_im_t));
    NPM_LOCK(lchip);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NPM, SYS_WB_APPID_NPM_SUBID_MASTER, 1);
    g_npm_master[lchip]->ecpu_npm_im_en = value;
    #if (SDK_WORK_PLATFORM == 0)
    ecpu_npm_im.type = CTC_NPM_IM_FLOW_PROP_MAX;
    ecpu_npm_im.profile_id = SYS_NPM_IM_GLOABL_ENABLE_PROFILE_ID;
    ecpu_npm_im.enable =value&0x1;
    ret = _sys_usw_npm_im_set_ecpu(lchip, &ecpu_npm_im);
    #endif
    NPM_UNLOCK(lchip);
    return ret;
}

int32
sys_usw_npm_im_get_ecpu_en(uint8 lchip, uint32* value)
{
    NPM_LOCK(lchip);
    *value=g_npm_master[lchip]->ecpu_npm_im_en;
    NPM_UNLOCK(lchip);
    return CTC_E_NONE;
}
#endif

int32
sys_usw_npm_im_get_flow_property(uint8 lchip,  ctc_npm_im_flow_property_t* p_npm_im_pro)
{
    int32 ret = CTC_E_NONE;
    SYS_NPM_INIT_CHECK(lchip);
    NPM_LOCK(lchip);
    ret = _sys_usw_npm_im_get_flow_property(lchip,p_npm_im_pro);
    NPM_UNLOCK(lchip);
    return ret;
}

int32
sys_usw_npm_im_show_flow_db(uint8 lchip, uint32 flow_id, uint8 is_all)
{
    uint16 entry_num = 0;
    sys_traverse_t user_data;
    sys_npm_im_flow_hash_t* p_im_flow_hash = NULL;

    sal_memset(&user_data, 0, sizeof(sys_traverse_t));

    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NPM_INIT_CHECK(lchip);
    CTC_MAX_VALUE_CHECK(flow_id, 0xFFFFF);

    NPM_LOCK(lchip);
    if(is_all)
    {
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"============== NPM IM FLOW Overall Status ==============\n");
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"NPM IM Lbit Table Name :IpeAclMplsInBandOamLFlagStatusCtl(1)\n");
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"NPM IM Dbit Table Name :IpeAclMplsInBandOamDFlagStatus(1024)\n");
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"No.   Flow-Id  Flow-Node  Im-Type  D-Prof-Id  D-Prof-Id-Valid  L-Prof-Id  "
                                             "FIH-Type L-Valid  L-Flag  D-Flag  Stats-Id  Acl-Entry-Id Acl-Valid\n");
        user_data.data = (void*)&(entry_num);
        user_data.value1 = lchip;
        ctc_hash_traverse(g_npm_master[lchip]->p_npm_im_flow_hash, _sys_usw_npm_im_dump_flow_info_cb, (void*) (&user_data));
    }
    else
    {
        p_im_flow_hash = _sys_usw_npm_ilm_get_im_flow_hash(lchip, flow_id);
        if(p_im_flow_hash == NULL)
        {
            SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Flow Id not exist \n");
            NPM_UNLOCK(lchip);
            return CTC_E_NOT_EXIST;
        }
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"================= NPM IM FLOW =================\n");
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"NPM IM Lbit Table Name :IpeAclMplsInBandOamLFlagStatusCtl(1)\n");
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"NPM IM Dbit Table Name :IpeAclMplsInBandOamDFlagStatus(1024)\n");
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"Flow-Id  Flow-Node  Im-Type  D-Prof-Id  D-Prof-Id-Valid  L-Prof-Id  "
                                             "FIH-Type L-Valid  L-Flag  D-Flag  Stats-Id  Acl-Entry-Id Acl-Valid\n");
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"%-7u  %-9u  %-7u  %-9d  %-15d  %-9d  %-8d  %-7u  %-6u  %-6u  %-8u  %-12u %-9u\n",\
                        p_im_flow_hash->flow_id,p_im_flow_hash->flow_type,p_im_flow_hash->type,\
                        p_im_flow_hash->delay_prof_id,p_im_flow_hash->delay_prof_id_valid,p_im_flow_hash->loss_prof_id,\
                        p_im_flow_hash->fih_type,p_im_flow_hash->l_valid,p_im_flow_hash->l_flag,p_im_flow_hash->d_flag,\
                        p_im_flow_hash->stats_id,p_im_flow_hash->acl_entry_id,p_im_flow_hash->acl_bind_en);
    }

    NPM_UNLOCK(lchip);

    return CTC_E_NONE;
}

int32
sys_usw_npm_im_get_flow(uint8 lchip, uint32 flow_id, void* p_npm_im_flow)
{
    sys_npm_im_flow_hash_t* p_im_flow_hash = NULL;

    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NPM_INIT_CHECK(lchip);
    CTC_PTR_VALID_CHECK(p_npm_im_flow);
    NPM_LOCK(lchip);

    p_im_flow_hash = _sys_usw_npm_ilm_get_im_flow_hash(lchip, flow_id);
    if(p_im_flow_hash == NULL)
    {
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Flow Id not exist \n");
        NPM_UNLOCK(lchip);
        return CTC_E_NOT_EXIST;
    }

    sal_memcpy(p_npm_im_flow, p_im_flow_hash, sizeof(sys_npm_im_flow_hash_t));

    NPM_UNLOCK(lchip);

    return CTC_E_NONE;
}

int32
sys_usw_npm_im_set_flow(uint8 lchip, void* p_npm_im_flow, uint32 bind_en)
{
    sys_npm_im_flow_hash_t* p_im_flow_hash_tmp = (sys_npm_im_flow_hash_t*)p_npm_im_flow;
    sys_npm_im_flow_hash_t* p_im_flow_hash = NULL;
    
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NPM_INIT_CHECK(lchip);
    CTC_PTR_VALID_CHECK(p_npm_im_flow);
    NPM_LOCK(lchip);

    if (bind_en)
    {
        p_im_flow_hash = _sys_usw_npm_ilm_get_im_flow_hash(lchip, p_im_flow_hash_tmp->flow_id);
        if(p_im_flow_hash == NULL)
        {
            SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Flow Id not exist \n");
            NPM_UNLOCK(lchip);
            return CTC_E_NOT_EXIST;
        }

        sal_memcpy(p_im_flow_hash, p_im_flow_hash_tmp, sizeof(sys_npm_im_flow_hash_t));
        p_im_flow_hash->acl_bind_en = 1;
    }
    else
    {
        sys_traverse_t user_data;
        int32 ret = CTC_E_NONE;

        sal_memset(&user_data, 0, sizeof(user_data));
        user_data.value1 = p_im_flow_hash_tmp->acl_entry_id;
        ret = ctc_hash_traverse(g_npm_master[lchip]->p_npm_im_flow_hash, _sys_usw_npm_im_cmp_acl_entry_id, (void*) (&user_data));
        if (0 == ret)
        {
            NPM_UNLOCK(lchip);
            return CTC_E_NOT_EXIST;
        }
    }
    NPM_UNLOCK(lchip);

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_npm_wb_im_flow_hash_mapping_info(sys_wb_npm_im_flow_hash_t*p_wb_npmim_flow_info, sys_npm_im_flow_hash_t*p_npm_im_flow_info, uint8 sync)
{
    if (sync)
    {
        p_wb_npmim_flow_info->flow_id = p_npm_im_flow_info->flow_id;
        p_wb_npmim_flow_info->flow_type = p_npm_im_flow_info->flow_type;
        p_wb_npmim_flow_info->loss_prof_id = p_npm_im_flow_info->loss_prof_id;
        p_wb_npmim_flow_info->fih_type = p_npm_im_flow_info->fih_type;
        p_wb_npmim_flow_info->stats_id = p_npm_im_flow_info->stats_id;
        p_wb_npmim_flow_info->delay_prof_id = p_npm_im_flow_info->delay_prof_id;
        p_wb_npmim_flow_info->delay_prof_id_valid = p_npm_im_flow_info->delay_prof_id_valid;
        p_wb_npmim_flow_info->metadata = p_npm_im_flow_info->metadata;
        p_wb_npmim_flow_info->igs_stats_ptr = p_npm_im_flow_info->igs_stats_ptr;
        p_wb_npmim_flow_info->egs_stats_ptr = p_npm_im_flow_info->egs_stats_ptr;

        p_wb_npmim_flow_info->type = p_npm_im_flow_info->type;
        p_wb_npmim_flow_info->l_valid = p_npm_im_flow_info->l_valid;
        p_wb_npmim_flow_info->l_flag = p_npm_im_flow_info->l_flag;
        p_wb_npmim_flow_info->d_flag = p_npm_im_flow_info->d_flag;
        p_wb_npmim_flow_info->acl_entry_id = p_npm_im_flow_info->acl_entry_id;
        p_wb_npmim_flow_info->acl_bind_en = p_npm_im_flow_info->acl_bind_en;
        p_wb_npmim_flow_info->rsv = 0;
        p_wb_npmim_flow_info->rsv1 = 0;
    }
    else
    {
        p_npm_im_flow_info->flow_id = p_wb_npmim_flow_info->flow_id;
        p_npm_im_flow_info->flow_type = p_wb_npmim_flow_info->flow_type;
        p_npm_im_flow_info->loss_prof_id = p_wb_npmim_flow_info->loss_prof_id;
        p_npm_im_flow_info->fih_type = p_wb_npmim_flow_info->fih_type;
        p_npm_im_flow_info->stats_id = p_wb_npmim_flow_info->stats_id;
        p_npm_im_flow_info->delay_prof_id = p_wb_npmim_flow_info->delay_prof_id;
        p_npm_im_flow_info->delay_prof_id_valid = p_wb_npmim_flow_info->delay_prof_id_valid;
        p_npm_im_flow_info->metadata = p_wb_npmim_flow_info->metadata;
        p_npm_im_flow_info->igs_stats_ptr = p_wb_npmim_flow_info->igs_stats_ptr;
        p_npm_im_flow_info->egs_stats_ptr = p_wb_npmim_flow_info->egs_stats_ptr;

        p_npm_im_flow_info->type = p_wb_npmim_flow_info->type;
        p_npm_im_flow_info->l_valid = p_wb_npmim_flow_info->l_valid;
        p_npm_im_flow_info->l_flag = p_wb_npmim_flow_info->l_flag;
        p_npm_im_flow_info->d_flag = p_wb_npmim_flow_info->d_flag;
        p_npm_im_flow_info->acl_entry_id = p_wb_npmim_flow_info->acl_entry_id;
        p_npm_im_flow_info->acl_bind_en = p_wb_npmim_flow_info->acl_bind_en;
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_npm_im_sync_flow_hash_func(sys_npm_im_flow_hash_t* p_npm_im_flow_info, void *user_data)
{
   uint32 max_entry_cnt = 0;
   sys_wb_npm_im_flow_hash_t* p_wb_npm_im_flow_info;
   ctc_wb_data_t *wb_data = (ctc_wb_data_t *)(user_data);

   max_entry_cnt = wb_data->buffer_len / (wb_data->key_len + wb_data->data_len);
   p_wb_npm_im_flow_info = (sys_wb_npm_im_flow_hash_t *)wb_data->buffer + wb_data->valid_cnt;
   CTC_ERROR_RETURN(_sys_usw_npm_wb_im_flow_hash_mapping_info(p_wb_npm_im_flow_info, p_npm_im_flow_info, 1));
   if (++wb_data->valid_cnt == max_entry_cnt)
   {
       CTC_ERROR_RETURN(ctc_wb_add_entry(wb_data));
       wb_data->valid_cnt = 0;
   }
   return CTC_E_NONE;
}

int32
sys_usw_npm_im_wb_init(uint8 lchip)
{
    ctc_wb_appid_t  appid;
    sal_memset(&appid,0,sizeof(appid));

    if (DRV_FROM_TMM(lchip))
    {
        appid.app_id = lchip << 16 | CTC_WB_APPID(CTC_FEATURE_NPM, SYS_WB_APPID_NPM_SUBID_IM_FLOW_HASH) ;
        appid.entry_num = SYS_WB_NPM_SUBID_IM_FLOW_HASH_NUM;
        appid.entry_size  = sizeof(sys_wb_npm_im_flow_hash_t);
        appid.rt_en = 0;
        ctc_wb_add_appid(lchip, &appid);
    }

    return CTC_E_NONE;
}

int32
sys_usw_npm_im_wb_sync(uint8 lchip, uint32 app_id)
{
    int32 ret = CTC_E_NONE;
    ctc_wb_data_t wb_data = {0};
    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    CTC_WB_ALLOC_BUFFER(&wb_data.buffer);

    if ((app_id == 0 || CTC_WB_SUBID(app_id) == SYS_WB_APPID_NPM_SUBID_IM_FLOW_HASH)&& DRV_FROM_TMM(lchip))
    {
         /*sync im flow hash*/
        CTC_WB_INIT_DATA_T((&wb_data), sys_wb_npm_im_flow_hash_t, CTC_FEATURE_NPM, SYS_WB_APPID_NPM_SUBID_IM_FLOW_HASH);
        wb_data.valid_cnt = 0;
        CTC_ERROR_GOTO(ctc_hash_traverse(g_npm_master[lchip]->p_npm_im_flow_hash, (hash_traversal_fn) _sys_usw_npm_im_sync_flow_hash_func, (void *)&wb_data), ret, done);
        if (wb_data.valid_cnt > 0)
        {
            CTC_ERROR_GOTO(ctc_wb_add_entry(&wb_data), ret, done);
            wb_data.valid_cnt = 0;
        }
        CTC_WB_SYNC_END_DATA(CTC_FEATURE_NPM, SYS_WB_APPID_NPM_SUBID_IM_FLOW_HASH);
    }
done:
    CTC_WB_FREE_BUFFER(wb_data.buffer);

    return ret;
}

int32
sys_usw_npm_im_wb_restore(uint8 lchip)
{
    int32 ret = CTC_E_NONE;
    uint32 entry_cnt = 0;
    ctc_wb_query_t    wb_query;
    sys_usw_opf_t opf;
    sys_wb_npm_im_flow_hash_t wb_im_flow_hash = {0};
    sys_npm_im_flow_hash_t* p_im_flow_hash = NULL;

    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    /*restore master*/
    CTC_WB_ALLOC_BUFFER(&wb_query.buffer);

    if(DRV_FROM_TMM(lchip))
    {
        /*restore im flow hash*/
        CTC_WB_INIT_QUERY_T((&wb_query), sys_wb_npm_im_flow_hash_t, CTC_FEATURE_NPM, SYS_WB_APPID_NPM_SUBID_IM_FLOW_HASH);
        CTC_WB_QUERY_ENTRY_BEGIN((&wb_query));
        sal_memcpy((uint8*)&wb_im_flow_hash, (uint8*)(wb_query.buffer) + entry_cnt * (wb_query.key_len + wb_query.data_len), wb_query.key_len + wb_query.data_len);
        entry_cnt++;
        p_im_flow_hash = mem_malloc(MEM_NPM_MODULE, sizeof(sys_npm_im_flow_hash_t));
        if (NULL == p_im_flow_hash)
        {
            ret = CTC_E_NO_MEMORY;
            goto done;
        }
        sal_memset(p_im_flow_hash, 0, sizeof(sys_npm_im_flow_hash_t));
        CTC_ERROR_GOTO(_sys_usw_npm_wb_im_flow_hash_mapping_info(&wb_im_flow_hash, p_im_flow_hash, 0), ret, done);
        if (p_im_flow_hash->delay_prof_id_valid)
        {
            opf.pool_type  = g_npm_master[lchip]->opf_type_im_delay;
            opf.pool_index  = 0;
            sys_usw_opf_alloc_offset_from_position(lchip, &opf, 1, p_im_flow_hash->delay_prof_id);
        }
        if (p_im_flow_hash->flow_type)
        {
            opf.pool_type  = g_npm_master[lchip]->opf_type_im_loss;
            opf.pool_index  = 0;
            sys_usw_opf_alloc_offset_from_position(lchip, &opf, 2, p_im_flow_hash->metadata);
        }
        if (NULL == ctc_hash_insert(g_npm_master[lchip]->p_npm_im_flow_hash, p_im_flow_hash))
        {
            ret = CTC_E_NO_MEMORY;
            goto done;
        }
        CTC_WB_QUERY_ENTRY_END((&wb_query));
    }
    CTC_WB_FREE_BUFFER(wb_query.buffer);

    return ret;
done:
    CTC_WB_FREE_BUFFER(wb_query.buffer);

    if (p_im_flow_hash)
    {
        mem_free(p_im_flow_hash);
    }

    return ret;
}

int32
sys_usw_npm_im_get_ip_info(uint8 lchip, sys_com_npm_im_ip_t* p_ip_info)
{
    SYS_NPM_INIT_CHECK(lchip);
    CTC_PTR_VALID_CHECK(p_ip_info);

    SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    NPM_LOCK(lchip);
    p_ip_info->im_proto = g_npm_master[lchip]->im_protocol;
    sal_memcpy(p_ip_info->sink_node_fp_id, g_npm_master[lchip]->sink_node_fp_id, sizeof(uint32)*SYS_IM_MAX_TYPE);
    sal_memcpy(p_ip_info->src_node_delay_fp_id, g_npm_master[lchip]->src_node_delay_fp_id, sizeof(uint32)*SYS_IM_MAX_TYPE);
    sal_memcpy(p_ip_info->src_node_fp_id, g_npm_master[lchip]->src_node_fp_id, sizeof(uint32)*SYS_IM_MAX_TYPE);
    NPM_UNLOCK(lchip);

    return CTC_E_NONE;
}

int32
sys_usw_npm_im_init(uint8 lchip, ctc_npm_global_cfg_t* p_npm_global_cfg)
{
    int32 ret = CTC_E_NONE;
    uint32 entry_num = 0;
    sys_usw_opf_t opf;

    g_npm_master[lchip]->im_protocol = p_npm_global_cfg->im_protocol;
#if defined E_UNIT && (FEATURE_MODE == 0)
    sys_usw_eunit_regitser_isr(lchip, SYS_EUNIT_NPM_IM, sys_usw_npm_im_loss_isr);
    CTC_ERROR_GOTO(sys_usw_interrupt_register_event_cb(lchip, CTC_EVENT_NPM_IM, sys_usw_npm_im_event_cb), ret, roll_back_0);
    CTC_ERROR_GOTO(SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_SET_ECPU_EN, sys_usw_npm_im_set_ecpu_en), ret, roll_back_0);
    CTC_ERROR_GOTO(SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_GET_ECPU_EN, sys_usw_npm_im_get_ecpu_en), ret, roll_back_0);
#endif
    /* install register cb */
    CTC_ERROR_GOTO(SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_FLOW_TO_ACL, sys_usw_npm_im_get_flow), ret, roll_back_0);
    CTC_ERROR_GOTO(SYS_CB_REGISTER(lchip, SYS_CB_ACL_TO_NPM_IM_FLOW, sys_usw_npm_im_set_flow), ret, roll_back_0);
    CTC_ERROR_GOTO(SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_SET_EN, sys_usw_npm_im_set_flow_en), ret, roll_back_0);
    CTC_ERROR_GOTO(SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_GET_EN, sys_usw_npm_im_get_flow_en), ret, roll_back_0);
    CTC_ERROR_GOTO(SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_GET_FLOW_ID, sys_usw_npm_im_get_flow_id_with_metadata), ret, roll_back_0);
    CTC_ERROR_GOTO(SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_SET_LOSS_PROFILE, sys_usw_npm_im_set_loss_profile_interval), ret, roll_back_0);
    CTC_ERROR_GOTO(SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_GET_LOSS_PROFILE, sys_usw_npm_im_get_loss_profile_interval), ret, roll_back_0);
    CTC_ERROR_GOTO(SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_GET_IP_INFO, sys_usw_npm_im_get_ip_info), ret, roll_back_0);
    /*npm_im_flow_hash*/
    g_npm_master[lchip]->p_npm_im_flow_hash  = ctc_hash_create(
            SYS_NPM_IM_MAX_SESSION/64,
            64,
            (hash_key_fn)_sys_usw_npm_im_flow_hash_make,
            (hash_cmp_fn)_sys_usw_npm_im_flow_hash_cmp);
    if (NULL == g_npm_master[lchip]->p_npm_im_flow_hash)
    {
        SYS_NPM_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "No Memory\n");
        ret = CTC_E_NO_MEMORY;
        goto roll_back_1;
    }

    /*Delay profile_id opf*/
    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    CTC_ERROR_GOTO(sys_usw_opf_init(lchip, &g_npm_master[lchip]->opf_type_im_delay, 1, "opf-npm-type-im-delay"), ret, roll_back_2);
    opf.pool_type  = g_npm_master[lchip]->opf_type_im_delay;
    opf.pool_index = 0;
    entry_num = SYS_NPM_IM_MAX_DELAY_PROFILE;
    CTC_ERROR_GOTO(sys_usw_opf_init_offset(lchip, &opf, 0, entry_num), ret, roll_back_2);

    return CTC_E_NONE;

roll_back_2:
    sys_usw_opf_deinit(lchip, g_npm_master[lchip]->opf_type_im_delay);
roll_back_1:
    ctc_hash_traverse_remove(g_npm_master[lchip]->p_npm_im_flow_hash, (hash_traversal_fn)_sys_usw_npm_im_flow_free_node_data, NULL);
    ctc_hash_free(g_npm_master[lchip]->p_npm_im_flow_hash);
roll_back_0:
    return ret;
}

int32
sys_usw_npm_im_deinit(uint8 lchip)
{
    LCHIP_CHECK(lchip);
    if (NULL == g_npm_master[lchip])
    {
        return CTC_E_NONE;
    }
    SYS_VCHIP_MASTER_DEINIT(lchip, g_npm_master, CTC_FEATURE_NPM);

    if (g_npm_master[lchip]->loss_flow)
    {
        mem_free(g_npm_master[lchip]->loss_flow);
        g_npm_master[lchip]->loss_flow = NULL;

        sys_usw_opf_deinit(lchip, g_npm_master[lchip]->opf_type_im_loss);
        g_npm_master[lchip]->opf_type_im_loss = 0;
    }
    sys_usw_interrupt_register_event_cb(lchip, CTC_EVENT_NPM_IM, NULL);
    SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_SET_ECPU_EN, NULL);
    SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_GET_ECPU_EN, NULL);
    /*free im_flow_hash*/
    ctc_hash_free2(g_npm_master[lchip]->p_npm_im_flow_hash, (hash_traversal_fn)_sys_usw_npm_im_flow_free_node_data, NULL);
    SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_FLOW_TO_ACL, NULL);
    SYS_CB_REGISTER(lchip, SYS_CB_ACL_TO_NPM_IM_FLOW, NULL);
    SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_SET_EN, NULL);
    SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_GET_EN, NULL);
    SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_GET_FLOW_ID, NULL);
    SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_SET_LOSS_PROFILE, NULL);
    SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_GET_LOSS_PROFILE, NULL);
    SYS_CB_REGISTER(lchip, SYS_CB_NPM_IM_GET_IP_INFO, NULL);
    sys_usw_opf_deinit(lchip, g_npm_master[lchip]->opf_type_im_delay);

    return CTC_E_NONE;
}

#endif/*FEATURE_MODE==0*/

